package com.glp.work.flow.listener;

import com.alibaba.fastjson.JSON;
import com.glp.common.reponse.BaseResult;
import com.glp.fbs.api.dto.appInfo.AppUserResp;
import com.glp.fbs.api.dto.appInfo.BusinessInfo;
import com.glp.fbs.api.dto.user.PersonInfoDto;
import com.glp.fbs.api.dto.user.PersonInfoWithAppReq;
import com.glp.work.flow.constant.*;
import com.glp.work.flow.exception.APIException;
import com.glp.work.flow.mapper.WfPlatformDefMapper;
import com.glp.work.flow.mapper.WfTaskAssignMapper;
import com.glp.work.flow.pojo.*;
import com.glp.work.flow.request.ProcessStatusRequest;
import com.glp.work.flow.request.TaskAssignInfoDTO;
import com.glp.work.flow.service.*;
import com.glp.work.flow.service.client.PermissionClient;
import com.glp.work.flow.utils.DateUtils;
import com.glp.work.flow.workflow.plugin.flowable.constant.FlowConstant;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.flowable.editor.language.json.converter.util.CollectionUtils;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.task.Comment;
import org.flowable.task.service.delegate.DelegateTask;
import org.flowable.task.service.delegate.TaskListener;
import org.flowable.variable.api.history.HistoricVariableInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import tk.mybatis.mapper.entity.Example;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 节点监听器
 *
 * @author pengjia
 * @version 2020年5月14日 下午5:04:42
 */
@Component
@Slf4j
public class AssignerTaskHandler implements TaskListener {

    private static final long serialVersionUID = -8688352881207375241L;

    public static final String ASSIGNER_TASK_LISTENER_IMPL = "com.glp.work.flow.listener.AssignerTaskHandler";

    private static OrderInfoService orderInfoService;

    private static SyncProcessStatusService syncProcessStatusService;

    private static TaskService taskService;

    private static HistoryService historyService;

    private static PermissionClient permissionService;

    private static UserService userService;

    private static RepositoryService repositoryService;

    private static WfPlatformDefMapper wfPlatformDefMapper;

    private static WfFormService wfFormService;

    private static WfTaskAssignMapper wfTaskAssignMapper;

    @Override
    public void notify(DelegateTask delegateTask) {
        /*
         * 流程第一次发起会分配用户节点任务，当完成任务时，会分配下个用户节点的任务
         */
        if (AssignerTaskHandler.EVENTNAME_CREATE.equals(delegateTask.getEventName())) {
            log.info("分配用节点信息");
            taskCreateEventHandler(delegateTask);
        } else if (AssignerTaskHandler.EVENTNAME_COMPLETE.equals(delegateTask.getEventName())) {
            log.info("完成任务");
            taskCompleteEventHandler(delegateTask);
        }
    }

    private void taskCreateEventHandler(DelegateTask delegateTask) {
        String proDefId = delegateTask.getProcessDefinitionId();
        String taskDefKey = delegateTask.getTaskDefinitionKey();
        log.info("当前节点是否为动态分配节点，后面的所有节点都按此用户分配");
        @SuppressWarnings("unchecked")
        List<String> userNos = (List<String>) delegateTask.getVariables().get(ProcessVariablesEnum.DYNAMIC_USER_ASSIGN.name());

        List<HistoricActivityInstance> histTask = getHistTask(delegateTask.getProcessInstanceId());
        if (CollectionUtils.isEmpty(histTask)) {
            log.info("发起工作流时：判断第一个节点是否按动态分配用户进行分配任务");
            @SuppressWarnings("unchecked")
            List<String> dynamicUserNos = (List<String>) delegateTask.getVariables().get(ProcessVariablesEnum.DYNAMIC_USER_ASSIGN_ONE.name());
            if (CollectionUtils.isNotEmpty(dynamicUserNos)) {
                userNos = dynamicUserNos;
            }
        } else {
            log.info("当前节点是否为第一个节点，根据历史");
            log.info("分配下个节点任务时，是否为第一个节点");
            HistoricActivityInstance historicActivityInstance = histTask.get(histTask.size() - 2);
            if (historicActivityInstance.getActivityId().equals(taskDefKey)) {
                @SuppressWarnings("unchecked")
                List<String> dynamicUserNos = (List<String>) delegateTask.getVariables().get(ProcessVariablesEnum.DYNAMIC_USER_ASSIGN_ONE.name());
                if (CollectionUtils.isNotEmpty(dynamicUserNos)) {
                    userNos = dynamicUserNos;
                }
            }
        }
        if (CollectionUtils.isEmpty(userNos)) {
            Example example = new Example(WfTaskAssign.class);
            example.createCriteria()
                    .andEqualTo("taskDefId", taskDefKey)
                    .andEqualTo("procDefId", proDefId);
            WfTaskAssign wfTaskAssign = wfTaskAssignMapper.selectOneByExample(example);
            log.info("【任务分配】当前节点配置信息:{}", wfTaskAssign);
            if (wfTaskAssign != null) {
                if (Constants.STATUS_1.equals(wfTaskAssign.getType())) {
                    List<WfTaskAssignUsers> userList = orderInfoService.queryTaskAssignUsers(proDefId, taskDefKey);
                    log.info("【任务分配】查询被分配任务的用户！根据流程定义ID：{}，任务定义KEY：{}，", proDefId, taskDefKey);
                    if (CollectionUtils.isNotEmpty(userList)) {
                        userNos = userList.stream().map(WfTaskAssignUsers::getUserNo).collect(Collectors.toList());
                        log.info("【任务分配】流程定义ID：{}，任务定义KEY：{}，被分配任务的用户：{}", proDefId, taskDefKey, userNos);
                        //任务分配
                        taskAllocation(delegateTask, userNos, null);
                    }
                } else {
                    log.info("【任务分配】查询被分配任务的角色！根据流程定义ID：{}，任务定义KEY：{}，", proDefId, taskDefKey);
                    List<WfTaskAssignRole> wfTaskAssignRoles = orderInfoService.queryTaskAssignRoles(proDefId, taskDefKey);
                    List<String> codes = wfTaskAssignRoles.stream().map(WfTaskAssignRole::getRoleCode).collect(Collectors.toList());
                    RoleCodes roleCodes = new RoleCodes();
                    roleCodes.setRoleCodeList(codes);
                    BaseResult<?> listBaseResult = permissionService.personInfosByRoleCodeList(roleCodes);
                    if (listBaseResult.getCode() != 200) {
                        throw new APIException(APICode.ERROR, "调用根据角色得到对应的用户列表失败！！");
                    }
                    @SuppressWarnings("unchecked")
                    List<Map<String, String>> data = (List<Map<String, String>>) listBaseResult.getData();
                    userNos = new ArrayList<String>();
                    for (Map<String, String> user : data) {
                        String userNo = user.get("userNo");
                        userNos.add(userNo);
                    }
                    if (CollectionUtils.isNotEmpty(codes)) {
                        log.info("【任务分配】流程定义ID：{}，任务定义KEY：{}，被分配任务的角色：{}，角色下的用户：{}", proDefId, taskDefKey, codes, userNos);
                        userNos = filterUser(wfTaskAssign, userNos, delegateTask);
                        taskAllocation(delegateTask, userNos, codes);
                    }
                }
            }
        } else {
            log.info("【动态任务分配】");
            taskAllocation(delegateTask, userNos, null);
        }

    }

    /***
     * @Description: 任务分配
     * @Param: [delegateTask, userNos, codes]
     * @return: void
     * @Author: 郭永伟
     * @Date: 2020/8/13
     */
    private void taskAllocation(DelegateTask delegateTask, List<String> userNos, List<String> codes) {
        if (CollectionUtils.isEmpty(userNos) && CollectionUtils.isEmpty(codes)) {
            throw new APIException(APICode.DATA_ERROR, "【任务分配查询】请指定任务分配用户或角色！");
        }
        String userNo = (String) delegateTask.getVariable("assignee");
        if (delegateTask.getName().contains(FlowConstant.COUNTERSIGN_NAME)) {
            log.info("会签任务分配！userNos={},user={}", userNos, userNo);
            delegateTask.addCandidateUser(userNo);
        } else {
            if (CollectionUtils.isNotEmpty(userNos) && CollectionUtils.isEmpty(codes)) {
                log.info("普通任务分配 用户！userNos={}", userNos);
                delegateTask.addCandidateUsers(userNos);
            } else if (CollectionUtils.isNotEmpty(codes)) {
                log.info("普通任务分配 角色！roleCods={}", codes);
                delegateTask.addCandidateGroups(codes);
            }
        }
        log.info("【任务分配】更新节点信息。taskName={}", delegateTask.getName());
        WfOrder wfOrder = orderInfoService.queryWfOrderByPorcessId(delegateTask.getProcessInstanceId());
        if (wfOrder != null) {
            WfOrder record = new WfOrder();
            record.setOrderStatus(OrderStatus.PROCESSING.getCode());
            record.setCurrentNode(delegateTask.getName() == null ? "" : delegateTask.getName());
            orderInfoService.updateWfOrder(delegateTask.getProcessInstanceId(), record);
        }
        log.info("【任务分配】同步节点信息。taskName={}", delegateTask.getName());
        String procDefKey = repositoryService.createProcessDefinitionQuery().processDefinitionId(delegateTask.getProcessDefinitionId()).active().singleResult().getKey();
        ProcessStatusRequest request = new ProcessStatusRequest();
        List<HistoricActivityInstance> histTask = getHistTask(delegateTask.getProcessInstanceId());
        if (CollectionUtils.isNotEmpty(histTask)) {
            HistoricActivityInstance historicActivityInstance = histTask.get(0);
            request.setPreviousNode(historicActivityInstance.getActivityName());
        }
        request.setProcessDefKey(procDefKey);
        request.setOperation((String) delegateTask.getVariables().get(FlowConstant.AUDIT_PASS));
        String createUser = null;
        Object submitter = delegateTask.getVariables().get(FlowConstant.SUBMITTER);
        if (submitter != null) {
            createUser = submitter.toString();
        }
        TaskAssignInfoDTO taskAssignInfo = new TaskAssignInfoDTO();
        taskAssignInfo.setRoleNos(codes);
        if (delegateTask.getName().contains(FlowConstant.COUNTERSIGN_NAME)) {
            userNos.clear();
            userNos.add(userNo);
            taskAssignInfo.setUserNos(userNos);
        } else {
            taskAssignInfo.setUserNos(userNos);
        }
        request.setTaskId(delegateTask.getId());
        request.setTaskAssignInfo(taskAssignInfo);
        request.setOrderId((String) delegateTask.getVariables().get(FlowConstant.ORDER_ID));
        request.setProcessId(delegateTask.getProcessInstanceId());
        request.setCurrentNode(delegateTask.getName());
        request.setLogo(FlowConstant.BEGIN);
        request.setMessageType(MessageTypeEnum.USER_TASK.getType());
        request.setSubmitUser(createUser);
        request.setTaskDefId(delegateTask.getTaskDefinitionKey());
        request.setProcessDefId(delegateTask.getProcessDefinitionId());
        if (delegateTask.getVariables() != null
                && delegateTask.getVariables().get(FlowConstant.APPID) != null) {
            syncProcessStatusService.syncProcessStatus((String) delegateTask.getVariables().get(FlowConstant.APPID), request);
        }
    }


    private void taskCompleteEventHandler(DelegateTask delegateTask) {
        String createUser = null;
        Object submitter = delegateTask.getVariables().get(FlowConstant.SUBMITTER);
        if (submitter != null) {
            createUser = submitter.toString();
        }
        ProcessStatusRequest request = new ProcessStatusRequest();
        WfOrder order = orderInfoService.queryWfOrderByPorcessId(delegateTask.getProcessInstanceId());
        request.setProcessDefKey(order.getProcDefKey());
        request.setProcessId(delegateTask.getProcessInstanceId());
        if (delegateTask.getVariables() != null
                && delegateTask.getVariables().get(FlowConstant.AUDIT_PASS) != null) {
            request.setOperation((String) delegateTask.getVariables().get(FlowConstant.AUDIT_PASS));
        }
        List<HistoricActivityInstance> histTask = getHistTask(delegateTask.getProcessInstanceId());
        if(CollectionUtils.isNotEmpty(histTask)){
            HistoricActivityInstance historicActivityInstance = histTask.get(0);
            request.setPreviousNode(historicActivityInstance.getActivityName());
        }
        request.setCurrentNode(delegateTask.getName());
        request.setIndex_1(order.getIndex_1());
        request.setIndex_2(order.getIndex_2());
        request.setIndex_3(order.getIndex_3());
        request.setUserNo(delegateTask.getAssignee());
        request.setTaskId(delegateTask.getId());
        request.setLogo(FlowConstant.END);
        request.setMessageType(MessageTypeEnum.USER_TASK.getType());
        request.setSubmitUser(createUser);
        request.setOrderId(order.getOrderId());
        request.setTaskDefId(delegateTask.getTaskDefinitionKey());
        request.setExecutionId(delegateTask.getExecutionId());
        request.setProcessDefId(delegateTask.getProcessDefinitionId());
        request.setStatus(OrderStatus.getEnum(order.getOrderStatus()));
        HistoricVariableInstance hisVarInstance = historyService.createHistoricVariableInstanceQuery().taskId(delegateTask.getId()).variableName(FlowConstant.HAND_WRITING_SIGNATURE_ATTACHMENT_NAME).singleResult();
        if (hisVarInstance != null
                && hisVarInstance.getValue() != null) {
            request.setHandWritingSignatureData((Map<String, String>) hisVarInstance.getValue());
        }
        if (StringUtils.isNotBlank(delegateTask.getExecutionId())) {
            String hisTaskId = historyService.createHistoricTaskInstanceQuery().executionId(delegateTask.getExecutionId()).orderByTaskCreateTime().desc().list().get(0).getId();
            log.info("历史任务ID={}", hisTaskId);
            if (StringUtils.isNotBlank(hisTaskId)) {
                List<Comment> commentList = taskService.getTaskComments(hisTaskId);
                if (CollectionUtils.isNotEmpty(commentList)) {
                    List<String> messageList = commentList.stream().map(Comment::getFullMessage).collect(Collectors.toList());
                    request.setComments(messageList);
                }
            }
        }

        log.info("【完成任务节点】同步流程状态。节点={}，操作={}，状态={}", delegateTask.getName(), request.getOperation(), request.getStatus());
        if (delegateTask.getVariables() != null
                && delegateTask.getVariables().get(FlowConstant.APPID) != null) {
            {
                WfPlatformDef wfPlatformDef = null;
                {
                    Example example2 = new Example(WfPlatformDef.class);
                    example2.createCriteria().andEqualTo("platformId", delegateTask.getVariables().get(FlowConstant.APPID));
                    wfPlatformDef = wfPlatformDefMapper.selectOneByExample(example2);
                    request.setUpdateTime(DateUtils.formatDate(DateUtils.getCurrent(), DateUtils.FORMAT_TIME));
                }
                if (wfPlatformDef.getType() == 0) {
                    log.info("【任务完成】获取表单信息！appId：{}，processId：{}", delegateTask.getVariables().get(FlowConstant.APPID), request.getProcessId());
                    WfFormExample wfFormExample = wfFormService.queryFormExampleByTaskId(request.getProcessId(), request.getTaskId());
                    if (wfFormExample != null) {
                        String formData = wfFormExample.getProcessData();
                        request.setFormData(formData);
                    } else {
                        log.info("【任务完成】无表单数据！appId：{}，processId：{}", delegateTask.getVariables().get(FlowConstant.APPID), request.getProcessId());
                    }
                }
            }
            syncProcessStatusService.syncProcessStatus((String) delegateTask.getVariables().get(FlowConstant.APPID), request);
        }

    }


    /***
     * @description : 获取开始节点和用户节点的历史任务
     * @params : [processesId]
     * @returns : java.util.List<org.flowable.engine.history.HistoricActivityInstance>
     * @author : 郭永伟
     * @date : 2020/9/14
     */
    public static List<HistoricActivityInstance> getHistTask(String processesId) {
        log.info("获取历史中的开始节点，用户节点，中间消息节点，根绝结束时间排序");
        List<HistoricActivityInstance> collect = historyService.createHistoricActivityInstanceQuery().processInstanceId(processesId)
                .list();
        if(CollectionUtils.isNotEmpty(collect)){
            collect = collect.stream().filter(historicActivityInstance -> Keys.START_EVENT.equals(historicActivityInstance.getActivityType())
                    || (Keys.USER_TASK.equals(historicActivityInstance.getActivityType()) && historicActivityInstance.getEndTime() != null)
                    || (Keys.INTERMEDIATE_CATCH_EVENT.equals(historicActivityInstance.getActivityType()) && historicActivityInstance.getEndTime() != null)).collect(Collectors.toList());
            collect.sort((a, b) -> b.getEndTime().compareTo(a.getEndTime()));
        }
        return collect;
    }

    private List<String> filterUser(WfTaskAssign wfTaskAssign, List<String> userNos, DelegateTask delegateTask) {
        log.info("根据任务分配规则过滤用户");
        String createUser = null;
        Object submitter = delegateTask.getVariables().get(FlowConstant.SUBMITTER);
        if (submitter != null) {
            createUser = submitter.toString();
        }
        String updateUser = null;
        Object updateUserNo = delegateTask.getVariables().get(FlowConstant.UPDATE_USER);
        if (updateUserNo != null) {
            updateUser = updateUserNo.toString();
        }
        String appId = delegateTask.getVariables().get(FlowConstant.APPID).toString();
        if (TaskingType.NONE.getCode().equals(wfTaskAssign.getTaskDefRule())) {
            log.info("无任务分配规则！taskDefKey：{}", wfTaskAssign.getTaskDefKey());
            return userNos;
        } else if (TaskingType.SUBMIT_SCOPE.getCode().equals(wfTaskAssign.getTaskDefRule())) {
            Object submitterDeptNo = delegateTask.getVariables().get(FlowConstant.SUBMITTER_DEPT_NO);
            if (submitterDeptNo != null) {
                String[] str = submitterDeptNo.toString().split(",");
                List<String> businessRangeCodes = Arrays.asList(str);
                log.info("按提交人限制业务范围！taskDefKey：{}", wfTaskAssign.getTaskDefKey());
                List<String> collect = filterUserByBusinessScopeCode(userNos, appId, businessRangeCodes);

                if (collect != null) {
                    return collect;
                }
            }
            return userNos;
        } else if (TaskingType.LAST_POST_SCOPE.getCode().equals(wfTaskAssign.getTaskDefRule())) {
            log.info("按上一岗限制业务范围！taskDefKey：{}", wfTaskAssign.getTaskDefKey());
            PersonInfoDto personInfo = userService.getPersonInfo(updateUser, appId);
            if (personInfo != null) {
                List<String> businessRangeCodes = personInfo.getBusinessRangeCodes();
                if (CollectionUtils.isNotEmpty(businessRangeCodes)) {
                    List<String> collect = filterUserByBusinessScopeCode(userNos, appId, businessRangeCodes);
                    if (collect != null) {
                        return collect;
                    }
                }
            }
            return userNos;
        } else if (TaskingType.SUBMIT_COLLAR.getCode().equals(wfTaskAssign.getTaskDefRule())) {
            log.info("按提交人限制上级！taskDefKey：{}", wfTaskAssign.getTaskDefKey());
            if (createUser != null && !"".equals(createUser)) {
                List<String> userList = new ArrayList<>();
                PersonInfoDto personInfo = userService.getPersonInfo(createUser, "");
                if (personInfo != null) {
                    String parentUserNo = personInfo.getParentUserNo();
                    userList.add(parentUserNo);
                    userNos.retainAll(userList);
                }
            }
            return userNos;
        } else if (TaskingType.LAST_POST_COLLAR.getCode().equals(wfTaskAssign.getTaskDefRule())) {
            log.info("按上一岗限制上级！taskDefKey：{}", wfTaskAssign.getTaskDefKey());
            PersonInfoDto personInfo = userService.getPersonInfo(updateUser, "");
            if (personInfo != null) {
                List<String> userList = new ArrayList<>();
                String parentUserNo = personInfo.getParentUserNo();
                userList.add(parentUserNo);
                userNos.retainAll(userList);
            }
            return userNos;
        }
        return userNos;
    }

    private List<String> filterUserByBusinessScopeCode(List<String> userNos, String appId, List<String> businessRangeCodes) {
        log.info("判断有哪些用户符合业务范围");
        PersonInfoWithAppReq req = new PersonInfoWithAppReq();
        req.setAppId(appId);
        req.setUserNoList(userNos);
        log.info("请求参数：{}", JSON.toJSONString(req));
        List<AppUserResp> personInfos = userService.getPersonWithBusinessList(req);
        log.info("响应结果：{}", JSON.toJSONString(personInfos));
        if (CollectionUtils.isNotEmpty(personInfos)) {
            List<AppUserResp> collect = personInfos.stream().filter(accountInfoDto -> {
                for (String s : businessRangeCodes) {
                    List<BusinessInfo> business = accountInfoDto.getBusiness();
                    if(CollectionUtils.isNotEmpty(business)){
                        for (BusinessInfo businessInfo : business) {
                            if(businessInfo.getCode().contains(s)){
                                return true;
                            }
                        }
                    }
                }
                return false;
            }).collect(Collectors.toList());
            log.info("按业务范围过滤结果：{}",JSON.toJSONString(collect));
            return collect.stream().map(AppUserResp::getUserNo).collect(Collectors.toList());
        }
        return userNos;
    }

    @Autowired
    public void setOrderInfoService(OrderInfoService orderInfoService) {
        AssignerTaskHandler.orderInfoService = orderInfoService;
    }

    @Autowired
    public void setSyncProcessStatusService(SyncProcessStatusService syncProcessStatusService) {
        AssignerTaskHandler.syncProcessStatusService = syncProcessStatusService;
    }

    @Autowired
    public void setTaskService(TaskService taskService) {
        AssignerTaskHandler.taskService = taskService;
    }

    @Autowired
    public void setHistoryService(HistoryService historyService) {
        AssignerTaskHandler.historyService = historyService;
    }

    @Autowired
    public void setPermissionService(PermissionClient permissionService) {
        AssignerTaskHandler.permissionService = permissionService;
    }

    @Autowired
    public void setPermissionService(UserService userService) {
        AssignerTaskHandler.userService = userService;
    }

    @Autowired
    public void setRepositoryService(RepositoryService repositoryService) {
        AssignerTaskHandler.repositoryService = repositoryService;
    }

    @Autowired
    public void setWfTaskAssignMapper(WfTaskAssignMapper wfTaskAssignMapper) {
        AssignerTaskHandler.wfTaskAssignMapper = wfTaskAssignMapper;
    }

    @Autowired
    public void setWfPlatformDefMapper(WfPlatformDefMapper wfPlatformDefMapper) {
        AssignerTaskHandler.wfPlatformDefMapper = wfPlatformDefMapper;
    }

    @Autowired
    public void setWfFormService(WfFormService wfFormService) {
        AssignerTaskHandler.wfFormService = wfFormService;
    }

}
